package com.iotechn.unimall.app.api.rechargeable;

import com.baomidou.mybatisplus.mapper.EntityWrapper;
import com.baomidou.mybatisplus.mapper.Wrapper;
import com.github.binarywang.wxpay.bean.order.WxPayMpOrderResult;
import com.github.binarywang.wxpay.bean.request.WxPayRefundRequest;
import com.github.binarywang.wxpay.bean.request.WxPayUnifiedOrderRequest;
import com.github.binarywang.wxpay.bean.result.WxPayRefundResult;
import com.github.binarywang.wxpay.constant.WxPayConstants;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.github.binarywang.wxpay.service.WxPayService;
import com.iotechn.unimall.biz.service.distribution.DistributionBizService;
import com.iotechn.unimall.biz.service.user.UserBizService;
import com.iotechn.unimall.core.exception.*;
import com.iotechn.unimall.core.util.GeneratorUtil;
import com.iotechn.unimall.core.util.MoneyUtils;
import com.iotechn.unimall.data.component.LockComponent;
import com.iotechn.unimall.data.domain.*;
import com.iotechn.unimall.data.enums.*;
import com.iotechn.unimall.data.mapper.*;
import com.iotechn.unimall.data.util.SessionUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Service
public class RechargeableAppServiceImpl implements RechargeableAppService {


    @Value("${com.iotechn.unimall.machine-no}")
    private String MACHINE_NO;
    @Value("${com.iotechn.unimall.env}")
    private String ENV;
    @Value("${com.iotechn.unimall.wx.mini.app-id}")
    private String wxMiNiAppid;

    @Value("${com.iotechn.unimall.wx.app.app-id}")
    private String wxAppAppid;

    @Value("${com.iotechn.unimall.wx.h5.app-id}")
    private String wxH5Appid;
    private Logger logger = LoggerFactory.getLogger(this.getClass());
    @Autowired
    private RechargeableMapper rechargeableMapper;
    @Autowired
    private RechargeableOrderMapper rechargeableOrderMapper;
    @Autowired
    private WxPayService wxPayService;
    @Autowired
    private UserBizService userBizService;
    @Autowired
    private LockComponent lockComponent;
    @Autowired
    private DistributionMapper distributionMapper;
    @Autowired
    private DistributionBalanceDetailMapper distributionBalanceDetailMapper;
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private CouponMapper couponMapper;
    @Autowired
    private RefundOrderMapper refundOrderMapper;
    @Autowired
    private UserCouponMapper userCouponMapper;
    @Autowired
    private DistributionBizService distributionBizService;


    private static final String TAKE_PAYRECHARGEABLE_LOCK="payRechargeable:";

    private static final String TAKE_PAYRECHARGEABLECUSTOM_LOCK="payRechargeableCustom:";


    @Override
    public List<RechargeableDO> getRechargeableDOList()   throws ServiceException {
        Wrapper<RechargeableDO> wrapper = new EntityWrapper<RechargeableDO>();
        wrapper.eq("status",1);
        List<RechargeableDO> rechargeableDOS = rechargeableMapper.selectList(wrapper) ;
        return rechargeableDOS;
    }

    /**
     * 定额充值活动接口
     * @param rechargeableDO
     * @return
     * @throws ServiceException
     */
    @Override
    public String payRechargeable(RechargeableDO rechargeableDO,String channel,Long userId)  throws ServiceException {
        if (lockComponent.tryLock(TAKE_PAYRECHARGEABLE_LOCK + userId, 1)) {
            try {
                Date now=new Date();
                RechargeableOrderDO rechargeableOrderDO=new RechargeableOrderDO();
                rechargeableDO = rechargeableMapper.selectById(rechargeableDO.getId());
                rechargeableOrderDO.setGmtCreate(now);
                rechargeableOrderDO.setGmtUpdate(now);
                rechargeableOrderDO.setChannel(channel);
                rechargeableOrderDO.setStatus(RechargeRewardOrderType.UNPAY.getCode());
                rechargeableOrderDO.setRechargeType(RechargeType.QUOTA.getCode());
                rechargeableOrderDO.setRechargeableId(rechargeableDO.getId());
                rechargeableOrderDO.setRechargePrice(rechargeableDO.getRechargeAmount());
                rechargeableOrderDO.setUserId(userId);
                String orderNo = GeneratorUtil.genOrderId(MACHINE_NO, ENV);
                rechargeableOrderDO.setOrderNo(orderNo);
                rechargeableOrderMapper.insert(rechargeableOrderDO);
                return rechargeableOrderDO.getOrderNo();
            } catch (Exception e) {
                logger.error("payRechargeable  >>>>>>>>>   微信定额充值失败",e);
                throw new AppServiceException(ExceptionDefinition.RECHARGEABLE_MAKE_ORDER_FAIL);
            } finally {
                lockComponent.retree(TAKE_PAYRECHARGEABLECUSTOM_LOCK + userId);
            }
        }
        throw new AppServiceException(ExceptionDefinition.RECHARGEABLE_FREQUENT_OPERATION);

    }

    /**
     * 自定义充值接口
     * @param amount
     * @return
     * @throws ServiceException
     */
    @Override
    public String payRechargeableCustom(String channel,Integer amount,Long userId) throws ServiceException {
        if (lockComponent.tryLock(TAKE_PAYRECHARGEABLECUSTOM_LOCK + userId, 1)) {
            try {
                RechargeableOrderDO rechargeableOrderDO=new RechargeableOrderDO();
                Date now=new Date();
                rechargeableOrderDO.setGmtCreate(now);
                rechargeableOrderDO.setGmtUpdate(now);
                rechargeableOrderDO.setChannel(channel);
                rechargeableOrderDO.setStatus(RechargeRewardOrderType.UNPAY.getCode());
                rechargeableOrderDO.setRechargeType(RechargeType.CUSTOM.getCode());
                rechargeableOrderDO.setRechargePrice(amount);
                rechargeableOrderDO.setUserId(userId);
                String orderNo = GeneratorUtil.genOrderId(MACHINE_NO, ENV);
                rechargeableOrderDO.setOrderNo(orderNo);
                rechargeableOrderMapper.insert(rechargeableOrderDO);
                return rechargeableOrderDO.getOrderNo();
            } catch (Exception e) {
               logger.error("payRechargeableCustom  >>>>>>>>>   微信自定义充值失败",e);
                throw new AppServiceException(ExceptionDefinition.RECHARGEABLE_MAKE_ORDER_FAIL);
            } finally {
                lockComponent.retree(TAKE_PAYRECHARGEABLECUSTOM_LOCK + userId);
            }

        }
        throw new AppServiceException(ExceptionDefinition.RECHARGEABLE_FREQUENT_OPERATION);

    }

    @Override
    public Object wxPrepay(String orderNo, String ip,Long userId) throws ServiceException {
        checkUser(userId);
        Date now = new Date();
        RechargeableOrderDO param=new RechargeableOrderDO();
        param.setOrderNo(orderNo);
        param.setUserId(userId);
        RechargeableOrderDO rechargeableOrderDO = rechargeableOrderMapper.selectOne(param);
        // 检测订单状态
        Integer status = rechargeableOrderDO.getStatus();
        if (status != RechargeRewardOrderType.UNPAY.getCode()) {
            throw new AppServiceException(ExceptionDefinition.RECHARGEABLE_ORDER_STATUS_NOT_SUPPORT_PAY);
        }
        Integer loginType = SessionUtil.getUser().getLoginType();
        String appId;
        String tradeType;
        if (UserLoginType.MP_WEIXIN.getCode() == loginType) {
            appId = wxMiNiAppid;
            tradeType = WxPayConstants.TradeType.JSAPI;
        } else if (UserLoginType.APP_WEIXIN.getCode() == loginType || UserLoginType.REGISTER.getCode() == loginType) {
            appId = wxAppAppid;
            tradeType = WxPayConstants.TradeType.APP;
        } else if (UserLoginType.H5_WEIXIN.getCode() == loginType) {
            appId = wxH5Appid;
            tradeType = WxPayConstants.TradeType.JSAPI;
        } else {
            throw new AppServiceException(ExceptionDefinition.ORDER_LOGIN_TYPE_NOT_SUPPORT_WXPAY);
        }

        Object result = null;
        try {
            WxPayUnifiedOrderRequest orderRequest = new WxPayUnifiedOrderRequest();
            orderRequest.setAppid(appId);
            orderRequest.setOutTradeNo(orderNo);
            orderRequest.setOpenid(SessionUtil.getUser().getOpenId());
            orderRequest.setBody("订单：" + orderNo);
            orderRequest.setTotalFee(rechargeableOrderDO.getRechargePrice());
            orderRequest.setSpbillCreateIp(ip);
            orderRequest.setTradeType(tradeType);
            orderRequest.setAttach(OrderBusinessType.RECHARGEORDER.getCode()+"");
            result = wxPayService.createOrder(orderRequest);
            if (result instanceof WxPayMpOrderResult) {
                String prepayId = ((WxPayMpOrderResult) result).getPackageValue();
                prepayId = prepayId.replace("prepay_id=", "");
                UserFormIdDO userFormIdDO = new UserFormIdDO();
                userFormIdDO.setFormId(prepayId);
                userFormIdDO.setUserId(userId);
                userFormIdDO.setOpenid(SessionUtil.getUser().getOpenId());
                userFormIdDO.setGmtUpdate(now);
                userFormIdDO.setGmtCreate(now);
                userBizService.setValidFormId(userFormIdDO);
            }
        } catch (WxPayException e) {
            logger.error("[微信支付] 异常", e);
            throw new ThirdPartServiceException(e.getErrCodeDes(), ExceptionDefinition.THIRD_PART_SERVICE_EXCEPTION.getCode());
        } catch (Exception e) {
            logger.error("[预付款异常]", e);
            throw new AppServiceException(ExceptionDefinition.ORDER_UNKNOWN_EXCEPTION);
        }
        return result;
    }

    /**
     * 根据userId 查看分销表内是否有账户
     * @param userId
     */
    public String checkUser(Long userId) throws ServiceException{
        Integer count = distributionMapper.selectCount(new EntityWrapper<DistributionDO>().eq("user_id", userId));
        if (count > 0) {
            return "ok";
        }
        UserDO userDO = userMapper.selectById(userId);
        Date now = new Date();
        DistributionDO distributionDO = new DistributionDO();
        distributionDO.setStatus(StatusType.ACTIVE.getCode());
        distributionDO.setBalance(0);
        distributionDO.setRealBalance(0);
        distributionDO.setTotalBalance(0);
        distributionDO.setTotalRealBalance(0);
        distributionDO.setFreezeBalance(0);
        distributionDO.setRealname(userDO.getNickname());
        distributionDO.setPhone(userDO.getPhone());
        distributionDO.setUserId(userId);
        distributionDO.setGmtUpdate(now);
        distributionDO.setGmtCreate(now);
        distributionDO.setAllowChild(1);
        distributionDO.setLevel(1);
        if (distributionMapper.insert(distributionDO) > 0) {
            return "ok";
        }
        throw new AppServiceException(ExceptionDefinition.APP_UNKNOWN_EXCEPTION);
    }


    @Override
    public Object getReward(String orderNo, Long userId) throws ServiceException {
        Map<String,String> map=new HashMap<>();
        List<RechargeableOrderDO> rechargeableOrderDOs = rechargeableOrderMapper.selectList(new EntityWrapper<RechargeableOrderDO>().eq("order_no", orderNo));
        RechargeableOrderDO rechargeableOrder=new RechargeableOrderDO();
        if(rechargeableOrderDOs == null || rechargeableOrderDOs.size() < 1){
            return null;
        }
        rechargeableOrder = rechargeableOrderDOs.get(0);
        //是否为已支付订单
        if(rechargeableOrder.getStatus().intValue() - RechargeRewardOrderType.COMPLETE.getCode() != 0){
            return null;
        }
        Double rechargeDP = MoneyUtils.div(rechargeableOrder.getRechargePrice().doubleValue(), 100d, 2);
        //活动定额充值
        if(rechargeableOrder.getRechargeableId() != null){
            Long rechargeableId = rechargeableOrder.getRechargeableId();
            RechargeableDO rechargeableDO = rechargeableMapper.selectById(rechargeableId);
            Integer rechargeRewardType = rechargeableDO.getRechargeRewardType();
            //现金奖励
            if(RechargeRewardType.REWARD.getCode().equals(rechargeRewardType)){
                Double rechargeAmountD = MoneyUtils.div(rechargeableDO.getRechargeAmount().doubleValue(), 100d);
                Double rewardAmountD = MoneyUtils.div(rechargeableDO.getRewardAmount().doubleValue(), 100d);
                final String rechargeAmount ="rechargeAmount";
                final String rewardAmount ="rewardAmount";
                map.put(rechargeAmount,rechargeAmountD+"");
                map.put(rewardAmount,rewardAmountD+"");
                return map;
            }
            //优惠券奖励
            if(RechargeRewardType.REWARDCOUPON.getCode().equals(rechargeRewardType)){
                Long rewardCouponId = rechargeableDO.getRewardCouponId();
                CouponDO couponDO = couponMapper.selectById(rewardCouponId);
                //优惠券类型
                final String couponType= "couponType";
                map.put(couponType,"满减券");
                //优惠券名称
                final String couponName= "couponName";
                map.put(couponName,couponDO.getDescription());
                //优惠券有效时间
                final String effective ="effective";
                //需要优化一下相对天数的优惠券
               /* String start = DateUtils.dateToString("yyyy-MM-dd", couponDO.getGmtStart());
                String end = DateUtils.dateToString("yyyy-MM-dd", couponDO.getGmtEnd());
                map.put(effective,start+"~"+end);
               */ //优惠券抵扣金额
                final String discount="discount";
                Double discountD = MoneyUtils.div(couponDO.getDiscount().doubleValue(), 100d, 2);
                map.put(discount,discountD+"");
            }
        }else{
            return null;
        }
        return map;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Object refundReward(String orderNo, Long userId) throws ServiceException {
        List<RechargeableOrderDO> rechargeableOrderDOs = rechargeableOrderMapper.selectList(new EntityWrapper<RechargeableOrderDO>().eq("order_no", orderNo));
        if(rechargeableOrderDOs == null || rechargeableOrderDOs.size() < 1){
            //无效订单
            return "无效订单";
        }
        RechargeableOrderDO rechargeableOrderDO = rechargeableOrderDOs.get(0);
        RefundOrderDO reorder=new RefundOrderDO();
        String reorderNo= GeneratorUtil.genOrderId(MACHINE_NO, ENV);
        reorder.setOrderRefundNo(reorderNo);
        reorder.setOrderNo(orderNo);
        reorder.setRefundPrice(rechargeableOrderDO.getPayPrice());
        reorder.setRefundReason(0);
        reorder.setRefundStatus(0);
        reorder.setRefundUserId(userId);
        reorder.setRefundUserName(userId+"");
        reorder.setStoreId(0L);
        reorder.setStoreUserId(0L);
        reorder.setIsOnline(0);
        reorder.setRefundChannel("退余额");
        reorder.setGmtUpdate(new Date());
        reorder.setGmtCreate(new Date());
        refundOrderMapper.insert(reorder);
        try {
            WxPayRefundRequest wxPayRefundRequest = new WxPayRefundRequest();
            wxPayRefundRequest.setAppid(wxMiNiAppid);
            wxPayRefundRequest.setOutTradeNo(orderNo);
            wxPayRefundRequest.setOutRefundNo(reorderNo);
            wxPayRefundRequest.setTotalFee(rechargeableOrderDO.getPayPrice());
            wxPayRefundRequest.setRefundFee(rechargeableOrderDO.getPayPrice());
            WxPayRefundResult wxPayRefundResult = wxPayService.refund(wxPayRefundRequest);
            if (!wxPayRefundResult.getReturnCode().equals("SUCCESS")) {
                logger.warn("[微信退款] 失败 : " + wxPayRefundResult.getReturnMsg());
                throw new AdminServiceException(wxPayRefundResult.getReturnMsg(),
                        ExceptionDefinition.THIRD_PART_SERVICE_EXCEPTION.getCode());
            }
            if (!wxPayRefundResult.getResultCode().equals("SUCCESS")) {
                logger.warn("[微信退款] 失败 : " + wxPayRefundResult.getReturnMsg());
                throw new AdminServiceException(wxPayRefundResult.getReturnMsg(),
                        ExceptionDefinition.THIRD_PART_SERVICE_EXCEPTION.getCode());
            }
        } catch (WxPayException e) {
            logger.warn("[微信退款] 失败 ");
            throw new AdminServiceException("[微信退款] 失败",
                    ExceptionDefinition.THIRD_PART_SERVICE_EXCEPTION.getCode());
        }
        //修改余额  和 优惠券
        Long rechargeableId = rechargeableOrderDO.getRechargeableId();
        RechargeableDO rechargeableDO = rechargeableMapper.selectById(rechargeableId);
        Integer rechargeRewardType = rechargeableDO.getRechargeRewardType();
        //奖励现金
        Integer refundRechargeAmount=rechargeableDO.getRechargeAmount();
        Integer refundRewardAmount=rechargeableDO.getRewardAmount();
        Integer refundtotal=refundRechargeAmount+refundRewardAmount;
        List<DistributionDO> distributionDOS = distributionMapper.selectList(new EntityWrapper<DistributionDO>().eq("user_id", userId));
        if(distributionDOS == null && distributionDOS.size() != 1){
            //找不到账户
            return "找不到账户";
        }
        DistributionDO distributionDO = distributionDOS.get(0);
        Integer currentBalance = distributionDO.getBalance() - refundRechargeAmount;
        if(currentBalance < 0){
                return  "余额不足";
        }
        if(RechargeRewardType.REWARD.getCode().equals(rechargeRewardType)){
            Integer realDeductionSum = distributionBizService.getRealDeductionSum(distributionDO, refundtotal);
            distributionMapper.decBalance(distributionDO.getId(),refundtotal,realDeductionSum);
        }
        //奖励优惠券
        if(RechargeRewardType.REWARDCOUPON.getCode().equals(rechargeRewardType)){
            Long rewardCouponId = rechargeableDO.getRewardCouponId();
            List<UserCouponDO> userCouponDOS = userCouponMapper.selectList(new EntityWrapper<UserCouponDO>().eq("user_id", userId).eq("coupon_id", rewardCouponId));
            for (UserCouponDO userCouponDO :userCouponDOS
                 ) {
                userCouponDO.setGmtUsed(new Date());
                userCouponDO.setOrderId(reorder.getId());
                userCouponMapper.updateById(userCouponDO);
            }
            Integer realDeductionSum = distributionBizService.getRealDeductionSum(distributionDO, refundRechargeAmount);
            distributionMapper.decBalance(distributionDO.getId(),refundRechargeAmount,realDeductionSum);
        }
        //添加余额流水
        DistributionBalanceDetailDO distributionBalanceDetail=new DistributionBalanceDetailDO();
        distributionBalanceDetail.setDistributionId(distributionDO.getId());
        distributionBalanceDetail.setOrderNo(reorderNo);
        distributionBalanceDetail.setBalanceDelta(refundtotal);
        distributionBalanceDetail.setRealBalanceDelta(rechargeableOrderDO.getPayPrice());
        distributionBalanceDetail.setFreezeBalanceDelta(0);
        distributionBalanceDetail.setBalance(currentBalance);
        distributionBalanceDetail.setRealBalance(distributionDO.getRealBalance() - rechargeableOrderDO.getPayPrice());
        distributionBalanceDetail.setTotalBalance(distributionDO.getTotalBalance() - refundRechargeAmount);
        distributionBalanceDetail.setTotalRealBalance(distributionDO.getTotalRealBalance() - rechargeableOrderDO.getPayPrice());
        distributionBalanceDetail.setFreezeBalance(0);
        distributionBalanceDetail.setDescription("充值退款 "+refundtotal+"元");
        distributionBalanceDetail.setType(DistributionBalanceDetailType.EXPENSE_DEDUCTION.getCode());
        distributionBalanceDetail.setUserId(userId);
        distributionBalanceDetail.setGmtUpdate(new Date());
        distributionBalanceDetail.setGmtCreate(new Date());
        distributionBalanceDetailMapper.insert(distributionBalanceDetail);
        return "完";
    }
}
